﻿Imports WumpusWorld_2._0.Domain
Imports WumpusWorld_2._0.Functions

Namespace Functions

    Public Class Agent

#Region " Enum "

        Public Enum AgentDirection
            Right = 1
            Down = 2
            Left = 3
            Up = 4
        End Enum

#End Region

#Region " Variables "

        Private ReadOnly _objGenerateWorld As New GenerateWorld
        Private _activeCell As Cell
        Private _cellArray As New Cells
        Private _direction As Integer
        Private _hasArrow As Boolean
        Private _hasGold As Boolean
        Private _isAlive As Boolean
        Private _points As Long
        Private _hasWon As Boolean


        'Events that affects the agent
        Public Event KilledByWumpus(ByVal sender As Object, ByVal e As EventArgs)
        Public Event KilledByPit(ByVal sender As Object, ByVal e As EventArgs)
        Public Event OutOfBound(ByVal sender As Object, ByVal e As EventArgs)
        Public Event OutOfAmmo(ByVal sender As Object, ByVal e As EventArgs)
        Public Event ShotOutside(ByVal sender As Object, ByVal e As EventArgs)
        Public Event WumpusMissed(ByVal sender As Object, ByVal e As EventArgs)
        Public Event WumpusKilled(ByVal sender As Object, ByVal e As EventArgs)
        Public Event GrabbedGold(ByVal sender As Object, ByVal e As EventArgs)
        Public Event GoldNotFound(ByVal sender As Object, ByVal e As EventArgs)
        Public Event Won(ByVal sender As Object, ByVal e As EventArgs)

#End Region

#Region " Properties "
        Public Property Direction() As Integer
            Get
                Return _direction
            End Get
            Set(ByVal value As Integer)
                If value > 4 Then
                    value -= 4
                ElseIf value < 1 Then
                    value += 4
                End If
                _direction = value
            End Set
        End Property

        Public Property hasArrow() As Boolean
            Get
                Return _hasArrow
            End Get
            Set(ByVal value As Boolean)
                _hasArrow = value
            End Set
        End Property
        Public Property hasGold() As Boolean
            Get
                Return _hasGold
            End Get
            Set(ByVal value As Boolean)
                _hasGold = value
            End Set
        End Property

        Public Property isAlive() As Boolean
            Get
                Return _isAlive
            End Get
            Set(ByVal value As Boolean)
                _isAlive = value
            End Set
        End Property

        Public Property points As Long
            Get
                Return _points
            End Get
            Set(ByVal value As Long)
                _points = value
            End Set
        End Property

        Public Property hasWon As Boolean
            Get
                Return _hasWon
            End Get
            Set(ByVal value As Boolean)
                _hasWon = value
            End Set
        End Property

#End Region

#Region "Event Generator and EventRaisers"
        ''' <summary>
        ''' This Sub generates the events that happends when the agent moves
        ''' </summary>
        ''' <param name="cell"></param>
        ''' <remarks></remarks>
        Public Sub EventGenerator(ByVal cell As Cell, ByVal gridsize As Integer)

            With (cell)
                If .hasAgent And .hasWumpus And MainWindow.WumpusAlive Then
                    Me.isAlive = False
                    Me.points -= 1000
                    OnKilledByWumpus(New EventArgs())

                ElseIf .hasAgent And .hasPit Then
                    Me.isAlive = False
                    Me.points -= 1000
                    OnKilledByPit(New EventArgs())
                ElseIf .hasAgent And .xPos = 0 And .yPos = gridsize - 1 And Me.hasGold Then
                    Me.hasWon = True
                    OnWon(New EventArgs())

                End If

            End With

        End Sub

        ''' <summary>
        '''  The following Subs raises the different events inflicted by the agent
        ''' </summary>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Protected Overridable Sub OnKilledByWumpus(ByVal e As EventArgs)
            RaiseEvent KilledByWumpus(Me, e)
        End Sub
        Protected Overridable Sub OnKilledByPit(ByVal e As EventArgs)
            RaiseEvent KilledByPit(Me, e)
        End Sub
        Protected Overridable Sub OnOutOfBound(ByVal e As EventArgs)
            RaiseEvent OutOfBound(Me, e)
        End Sub
        Protected Overridable Sub OnOutOfAmmo(ByVal e As EventArgs)
            RaiseEvent OutOfAmmo(Me, e)
        End Sub
        Protected Overridable Sub OnShotOutside(ByVal e As EventArgs)
            RaiseEvent ShotOutside(Me, e)
        End Sub
        Protected Overridable Sub OnWumpusMissed(ByVal e As EventArgs)
            RaiseEvent WumpusMissed(Me, e)
        End Sub
        Protected Overridable Sub OnWumpusKilled(ByVal e As EventArgs)
            RaiseEvent WumpusKilled(Me, e)
        End Sub
        Protected Overridable Sub OnGrabbedGold(ByVal e As EventArgs)
            RaiseEvent GrabbedGold(Me, e)
        End Sub
        Protected Overridable Sub OnGoldNotFound(ByVal e As EventArgs)
            RaiseEvent GoldNotFound(Me, e)
        End Sub
        Protected Overridable Sub OnWon(ByVal e As EventArgs)
            RaiseEvent Won(Me, e)
        End Sub

#End Region

#Region " Move "
        ''' <summary>
        ''' Sub that moves agent one cell to the right, if agent still will be inside legal grid
        ''' </summary>
        ''' <param name="world"></param>
        ''' <remarks></remarks>
        Public Sub MoveRight(ByVal world(,) As Cell)
            _activeCell = _cellArray.getActiveCell(world)

            If Not _activeCell.xPos + 2 > world.GetLength(0) Then
                world(_activeCell.xPos, _activeCell.yPos).hasAgent = False
                world(_activeCell.xPos + 1, _activeCell.yPos).hasAgent = True
                world(_activeCell.xPos + 1, _activeCell.yPos).isVisited = True

            Else
                _activeCell.bumpRight = True
                OnOutOfBound(New EventArgs())

            End If

            Me.points -= 1

        End Sub

        ''' <summary>
        '''  Sub that moves agent one cell to the left, if agent still will be inside legal grid
        ''' </summary>
        ''' <param name="world"></param>
        ''' <remarks></remarks>
        Public Sub MoveLeft(ByVal world(,) As Cell)

            _activeCell = _cellArray.getActiveCell(world)
            If Not _activeCell.xPos - 1 < 0 Then
                world(_activeCell.xPos, _activeCell.yPos).hasAgent = False
                world(_activeCell.xPos - 1, _activeCell.yPos).hasAgent = True
                world(_activeCell.xPos - 1, _activeCell.yPos).isVisited = True

                
            Else
                _activeCell.bumpLeft = True
                OnOutOfBound(New EventArgs())

            End If

            Me.points -= 1

        End Sub

        ''' <summary>
        '''  Sub that moves agent one cell Up, if agent still will be inside legal grid
        ''' </summary>
        ''' <param name="world"></param>
        ''' <remarks></remarks>
        Public Sub MoveUp(ByVal world(,) As Cell)

            _activeCell = _cellArray.getActiveCell(world)

            If Not _activeCell.yPos - 1 < 0 Then
                world(_activeCell.xPos, _activeCell.yPos).hasAgent = False
                world(_activeCell.xPos, _activeCell.yPos - 1).hasAgent = True
                world(_activeCell.xPos, _activeCell.yPos - 1).isVisited = True

            Else
                _activeCell.bumpUp = True
                OnOutOfBound(New EventArgs())

            End If

            Me.points -= 1

        End Sub

        ''' <summary>
        '''  Sub that moves agent one cell Down, if agent still will be inside legal grid
        ''' </summary>
        ''' <param name="world"></param>
        ''' <remarks></remarks>
        Public Sub MoveDown(ByVal world(,) As Cell)

            _activeCell = _cellArray.getActiveCell(world)

            If Not _activeCell.yPos + 2 > world.GetLength(0) Then
                world(_activeCell.xPos, _activeCell.yPos).hasAgent = False
                world(_activeCell.xPos, _activeCell.yPos + 1).hasAgent = True
                world(_activeCell.xPos, _activeCell.yPos + 1).isVisited = True

            Else
                _activeCell.bumpDown = True
                OnOutOfBound(New EventArgs())

            End If

            Me.points -= 1

        End Sub
#End Region

#Region " Turn "

        Public Sub TurnRight()
            Direction += 1
            Me.points -= 1
        End Sub

        Public Sub TurnLeft()
            Direction -= 1
            Me.points -= 1
        End Sub

#End Region

#Region " Shoot "

        Public Sub Shoot(ByVal world(,) As Cell)

            If _hasArrow = False Then
                OnOutOfAmmo(New EventArgs())
                Exit Sub
            End If

            _hasArrow = False
            _activeCell = _cellArray.getActiveCell(world)

            Select Case _direction

                Case AgentDirection.Right
                    ShootRight(world)

                Case AgentDirection.Down
                    ShootDown(world)

                Case AgentDirection.Left
                    ShootLeft(world)

                Case AgentDirection.Up
                    ShootUp(world)
            End Select

            Me.points -= 10

        End Sub

        Public Sub ShootRight(ByVal world(,) As Cell)

            If Not _activeCell.xPos + 2 > world.GetLength(0) Then
                Dim i As Integer = 1

                Do While (_activeCell.xPos + i <= world.GetLength(0) - 1)

                    If world(_activeCell.xPos + i, _activeCell.yPos).hasWumpus Then
                        MainWindow.WumpusAlive = False
                        OnWumpusKilled(New EventArgs())
                    End If
                    i += 1
                Loop

                If MainWindow.WumpusAlive = True Then
                    OnWumpusMissed(New EventArgs())
                End If

            Else
                OnShotOutside(New EventArgs())
            End If

        End Sub
        Public Sub ShootDown(ByVal world(,) As Cell)

            If Not _activeCell.yPos + 2 > world.GetLength(0) Then
                Dim i As Integer = 1

                Do While (_activeCell.yPos + i <= world.GetLength(1) - 1)

                    If world(_activeCell.xPos, _activeCell.yPos + i).hasWumpus Then
                        MainWindow.WumpusAlive = False
                        OnWumpusKilled(New EventArgs())
                    End If
                    i += 1
                Loop

                If MainWindow.WumpusAlive = True Then
                    OnWumpusMissed(New EventArgs())
                End If

            Else
                OnShotOutside(New EventArgs())
            End If

        End Sub
        Public Sub ShootLeft(ByVal world(,) As Cell)


            If Not _activeCell.xPos - 1 < 0 Then

                Dim i As Integer = 1

                Do While (_activeCell.xPos - i >= 0)

                    If world(_activeCell.xPos - i, _activeCell.yPos).hasWumpus Then
                        MainWindow.WumpusAlive = False
                        OnWumpusKilled(New EventArgs())
                    End If
                    i += 1
                Loop

                If MainWindow.WumpusAlive = True Then
                    OnWumpusMissed(New EventArgs())
                End If

            Else
                OnShotOutside(New EventArgs())
            End If

        End Sub
        Public Sub ShootUp(ByVal world(,) As Cell)

            If Not _activeCell.yPos - 1 < 0 Then


                Dim i As Integer = 1

                Do While (_activeCell.yPos - i >= 0)

                    If world(_activeCell.xPos, _activeCell.yPos - i).hasWumpus Then
                        MainWindow.WumpusAlive = False
                        OnWumpusKilled(New EventArgs())
                    End If
                    i += 1
                Loop

                If MainWindow.WumpusAlive = True Then
                    OnWumpusMissed(New EventArgs())
                End If

            Else
                OnShotOutside(New EventArgs())
            End If



        End Sub

#End Region

#Region " Grab "

        Public Sub GrabGold(ByVal world(,) As Cell, ByVal KB(,) As Cell)

            Dim activecellworld As Cell = _cellArray.getActiveCell(world)
            Dim activecellKB As Cell = _cellArray.getActiveCell(KB)

            If activecellKB.hasGold Then
                activecellKB.hasGold = False
                activecellKB.hasGlitter = False
                activecellworld.hasGold = False
                activecellworld.hasGlitter = False
                _hasGold = True
                OnGrabbedGold(New EventArgs())

                Me.points += 1000
            Else
                OnGoldNotFound(New EventArgs())
            End If

        End Sub

#End Region

    End Class
End Namespace